Understanding the Basics of Terraform Providers

Understand “providers” to manipulate cloud resources.

At its heart, Terraform is a platform for reconciling an expressed desired state with an external system. The way Terraform interacts with external APIs is through plugins called providers. A provider is responsible for describing the schema for its exposed resources, and implementing Create, Read, Update, and Delete (CRUD) interactions with external APIs. Providers enable Terraform to express nearly any external API’s resources as Terraform resources.

svg viewer

Through its thousands of community and verified providers, Terraform is able to manage resources including databases such as Redis, Cassandra, and MongoDB, cloud infrastructure for all major cloud service providers, communication and messaging services such as Discord and SendGrid, and a vast number of other providers. If you are interested, you can explore a listing of them in the Terraform Registry. You can simply write, plan, and apply your way to your desired infrastructure.

In this lesson, we will build on our experience of using a local provider and extend what we learned to use a provider that interacts with an external API. We will define the desired state for a set of cloud resources and provision them. We will need an Azure account for this lesson.

Defining and provisioning cloud resources#

Imagine that we want to deploy infrastructure to our cloud service provider. In this case, we're going to use Microsoft Azure via the hashicorp/azurerm provider. Let's start by authoring a simple main.tf file like the following:

The main.tf file

The preceding Terraform configuration file requires the hashicorp/azurerm provider and defines a resource group named mygroup in the West Europe region (a resource group is an Azure concept that groups infrastructure resources together).

To run the rest of the examples in this section, we will need an Azure account. If we do not have an Azure account, we can sign up for a free account with $200 of Azure credits.

/
main.tf
Executable main.tf file

Run the following commands in the terminal provided above.

First, log in with the Azure CLI using the command below:


The preceding command will log us into our Azure account and set the default context to our primary Azure subscription. To see what subscription is active, run the following:

The preceding command output shows the name of the subscription and other details about the current context of the Azure CLI. The azurerm provider will use the authentication context of the Azure CLI to interact with the Azure APIs.

Now that we have an authenticated Azure session on the Azure CLI, let's use init and apply to create our desired state. Within the directory containing the main.tf file, run the following:

terraform init will initialize the directory, pulling down the latest azurerm provider. By specifying the ~> 3.0 version constraint, Terraform is directed to install the latest version of the provider in the 3.0.x series.

After initialization, we will again be greeted with the plan for creating the desired resources. Once the plan is approved, the desired resources are created.

As we should see from the output, the resource group is created.

Note: If we are using a free Azure account, we may not have regional capacity in the specified location. We may need to use a different region such as centralus or northeurope. To find out more information on what region would be best for us, view the Azure geography guidance here on the Azure website.

Opening the Azure portal and navigating to the Resource groups view, we should see the following:

The created resource group in Azure
The created resource group in Azure

In the preceding screenshot, we can see our newly created Azure resource group, mygroup.

Let's see what new files have been added to our local directory after running init and apply:

The directory structure
The directory structure

We can see this in the terminal with this command:

Similar to the previous section, we can see the Terraform lock and state files. However, in the providers directory, we now see that the azurerm provider was installed.

Let's add some more resources and apply them. We can find a listing of all of the supported resources in the Azure provider documentation. We'll update the main.tf file to contain the following resources:

The updated main.tf code

Update the main.tf file you ran previously by running this command:

After this command, paste the contents of the updated main.tf and paste it into the terminal. Afterwards, press “Ctrl+C” to exit out of the command.

The resources added to the preceding main.tf file include two Azure resources, an App Service plan, a Linux web app, and one random_integer resource. The Azure App Service plan defines a regional deployment of computing infrastructure for running a Linux-based web application. The Azure Linux web app is associated with the Azure App Service plan and is configured to run a hello world NGINX demo container image. The random_integer resource is needed to provide some random input for the Fully Qualified Domain Name (FQDN) for the Linux web app.

Note the use of variables. For example, we use azurerm_resource_group.mygroup.name to provide the value for resource_group_name in the azure_service_plan resource. Variable usage helps to minimize the number of string literals in the configuration files. This is helpful when making a change because we can make it in one place rather than each occurrence of the string.

Also, note the use of an output variable, host_name. This instructs Terraform to output the host_name key with the value of azurerm_linux_web_app.myapp.default_hostname after the completion of terraform apply. We'll use this output to make it easier to open the website after it is provisioned.

Let's run terraform apply again and see what happens

Oh no! terraform apply responds with an error, informing us that we have a new provider added to the configuration that we didn't have last time. Run terraform init -upgrade, and the random module will be added:

You should see some output that shows Terraform installing the latest version of the hashicorp/random provider. Let's see what our directory looks like now that we've added the provider. We can do this in the terminal with the same command as stated prior.

Directory structure
Directory structure

As we can see, the random provider is now installed. Let's use apply again:

You will see an error related to our subscription ID. Take note of this ID and run this command replacing {your-subscription-id} with the one outputted in the terminal:

Now run apply again:

The things to note in the output are that we are creating each of the resources we described in main.tf, have provisioned successfully, and host_name contains a Universal Resource Identifier (URI) for accessing the newly deployed web application.

Take the host_name URI displayed in the terminal and open it in a browser. We should see the following:

NGINX running in Azure App Service
NGINX running in Azure App Service

If we go back to the Azure portal, we will also see the resources created within our resource group.

We hope you will take some time to experiment by defining and applying other resources. Once we get the hang of using providers and some basic syntax, Terraform is a joy to work with. When we are done with our resources, just run terraform destroy, and they will be deleted.

In this lesson, we learned some basics about using providers to manipulate cloud resources. We only need to use a couple of providers, but as discussed in the opening of the section, there are thousands of providers out there. It's very likely that we will be able to find a provider to solve our problem. However, there may be APIs and resources we would like to manage with Terraform without an existing provider.

An Introduction to IaC

Building a Pet Store Terraform Provider